package com.kehutong.payfees.admin;

import java.io.File;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import com.kehutong.common.util.Token;
import com.kehutong.payfees.service.ChargeRecordServiceImpl;
import com.kehutong.payfees.service.record.AccoutServiceImpl;
import com.kehutong.payfees.util.BasicClient;
import com.kehutong.payfees.util.ExcelUtil;
import com.kehutong.payfees.util.JDBCUtil;
import org.coraframework.authz.HasPermission;
import org.coraframework.converter.util.StringUtil;
import org.coraframework.inject.Inject;
import org.coraframework.json.JSONArray;
import org.coraframework.json.JSONObject;
import org.coraframework.mvc.MvcAction;
import org.coraframework.mvc.http.ReqMapping;
import org.coraframework.mvc.http.result.Result;
import org.coraframework.orm.Pool;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.Page;


import com.kehutong.common.ExcelHeaders;
import com.kehutong.common.Java8TimeUtils;
import com.kehutong.common.PageUtils;
import com.kehutong.common.math.CalculatorUtils;
import com.kehutong.payfees.entity.ChargeAnnex;
import com.kehutong.payfees.entity.ChargeBill;
import com.kehutong.payfees.entity.record.AccWater;
import com.kehutong.payfees.entity.record.Account;
import com.kehutong.payfees.entity.record.ChargeRecord;
import com.kehutong.payfees.enums.BillEnableState;
import com.kehutong.payfees.enums.BillPaidState;
import com.kehutong.payfees.enums.BillPayMethod;
import com.kehutong.payfees.enums.ChargeAnnexEntityType;
import com.kehutong.payfees.enums.ChargeAnnexType;
import com.kehutong.payfees.enums.WaterSource;
import com.kehutong.payfees.service.ChargeBillServiceImpl;
import org.coraframework.orm.jdbc.execute.entity.FindPage;

/**
 * 预存款账户
 */
@MvcAction
@ReqMapping("/admin/account")
public class AccountWaterAction {

    @Inject
    private AccoutServiceImpl accoutService;
    @Inject
    private ChargeBillServiceImpl chargeBillService;
    @Inject
    private ChargeRecordServiceImpl chargeRecordService;
    @Inject
    private JdbcSession jdbcSession;
    @Inject
    private BasicClient basicClient;

    /**
     * 房屋预存款账户分页列表
     */
    @HasPermission("account:house:view")
    @ReqMapping("/house/page")
    public Object pageHouseAccount(Token token, JSONObject req) throws Exception {
        List<String> departmentIds = basicClient.getDepartmentIdsFilterList(token, req.getString("departmentId"));
        if (departmentIds != null) {
            if (departmentIds.isEmpty()) {
                return Result.success(new Page<>());
            }
            req.put("departmentIds", departmentIds);
        }

        JSONArray array = basicClient.getHouses(token, req);

        List<JSONObject> list = array.stream().map(item->{
            JSONObject json = (JSONObject) item;
            return json;
        }).collect(Collectors.toList());

        Page<JSONObject> page = PageUtils.buildPage(req, list);

        for (JSONObject house : page.getList()) {
            Account houseAccount = accoutService.getHouseAccount(house.getString("id"));
            house.put("accountUseAmt", houseAccount.getUseAmt());
        }

        return Result.success(page);
    }

    /**
     * 房屋预存款账户列表导出
     */
    @HasPermission("account:house:view")
    @ReqMapping("/house/export")
    public Object exportHouseAccount(Token token, JSONObject req) throws Exception {
        List<String> departmentIds = basicClient.getDepartmentIdsFilterList(token, req.getString("departmentId"));
        if (departmentIds != null) {
            if (departmentIds.isEmpty()) {
                return Result.success(new Page<>());
            }
            req.put("departmentIds", departmentIds);
        }

        Map<String, JSONObject> communityMap = basicClient.getCommunityMap(token);

        JSONArray array = basicClient.getHouses(token, req);

        List<String[]> objList = new ArrayList<>(array.size());
        for (int i = 0;i < array.size();i++) {
             JSONObject house = (JSONObject) array.get(i);
        	 String[] l = new String[9];
        	 l[0] = String.valueOf(i+1);
             l[1] = communityMap.get(house.getString("communityNo")).getString("name");
             // 房屋信息
             l[2] = house.getString("buildName");
             l[3] = house.getString("unitName");
             l[4] = house.getString("floorName");
             l[5] = house.getString("name");
             l[6] = house.getString("ownerName");
             l[7] = house.getString("ownerMobile");

             Account ha = accoutService.getHouseAccount(house.getString("id"));
             l[8] = CalculatorUtils.formatMoneyString(ha.getUseAmt());
             objList.add(l);
        }

        File tmpFile = ExcelUtil.writeXlsFile("预存款账户列表导出.xls", ExcelHeaders.CHARGE_ACCOUNT_HOUSE_EXPORT_EXCEL_HEADER, objList);
        return Result.download(tmpFile);
    }

    /**
     * 预存款余额
     */
    @HasPermission("account:house:view")
    @ReqMapping("/house/page/use_amt_total")
    public Object sumUseAmt(Token token, JSONObject req) throws Exception {
        String departmentId = req.getString("departmentId");
        if(org.coraframework.util.Objects.isEmpty(departmentId)){
            return Result.success(CalculatorUtils.formatMoney(BigDecimal.ZERO));
        }

        List<String> departmentIds = basicClient.getDepartmentIdsFilterList(token, req.getString("departmentId"));
        if (departmentIds != null) {
            if (departmentIds.isEmpty()) {
                return Result.success(new Page<>());
            }
            req.put("departmentIds", departmentIds);
        }

        JSONArray array = basicClient.getHouses(token, req);

        BigDecimal useAmtTotal = array.stream()
                .map(obj -> {
                    JSONObject house = (JSONObject) obj;
                    Account houseAccount = accoutService.getHouseAccount(house.getString("id"));
                    return houseAccount.getUseAmt();
                }).reduce(BigDecimal.ZERO, BigDecimal::add);

        return Result.success(CalculatorUtils.formatMoney(useAmtTotal));
    }

    /**
     * 房屋信息
     */
    @HasPermission("account:house:view")
    @ReqMapping("/house/get")
    public Object getHouseAccount(Token token, String id) throws Exception {
        JSONObject house = basicClient.getHouseById(token, id);
        if (Objects.isNull(house)) {
            return Result.error(0, "不存在的房屋");
        }

        JSONObject community = basicClient.getCommunityById(token, house.getString("communityNo"));

        Account houseAccount = accoutService.getHouseAccount(house.getString("id"));

        JSONObject v = new JSONObject();
        v.put("id", house.getString("id"));
        // 小区
        v.put("communityName", community.getString("name"));
        // 房屋信息
        v.put("floorName", house.getString("floorName"));
        v.put("buildingName", house.getString("buildName"));
        v.put("unitName", house.getString("unitName"));
        v.put("houseName", house.getString("name"));
        //业主信息
        v.put("ownerName", house.getString("ownerName"));
        v.put("ownerMobile", house.getString("ownerMobile"));

        v.put("useAmt", CalculatorUtils.formatMoney(houseAccount.getUseAmt()));
        v.put("totalChargeAmt", accoutService.sumChargeTotal(house.getString("id")));

        return Result.success(v);
    }

    /**
     * 充值记录
     */
    @HasPermission("account:house:view")
    @ReqMapping("/charge_record/page")
    public Object pageChargeRecord(JSONObject req) {
        if (StringUtil.isBlank(req.getString("houseNo"))) {
            return Result.error(0, "请选择房屋");
        }

        FindPage<ChargeRecord> find = jdbcSession.findPage(ChargeRecord.class)
                .eq(req, "houseNo")
                .eq("result", true)
                .like(req, "transactionId")
                .order("chargeTime", "DESC")
                .page(req);

        JDBCUtil.between(req, find, "chargeTime");

        Page<ChargeRecord> data = find
                .in("bizType", WaterSource.CHONGZHI, WaterSource.CHARGE_BY_CASH)
                .exe();

        data.getList().forEach(cr -> {
            ChargeAnnex ca = jdbcSession.findOne(ChargeAnnex.class)
                    .eq("entityType", ChargeAnnexEntityType.CHARGE_RECORD)
                    .eq("entityId", cr.getId())
                    .eq("type", ChargeAnnexType.MANUAL_CHARGE_VOUCHER)
                    .exe();
            if (ca != null) {
                cr.setFileIds(ca.getFileIds());
            }
        });

        return Result.success(data);
    }

    /**
     * 支付记录
     */
    @HasPermission("account:house:view")
    @ReqMapping("/charge_bill/page")
    public Object pageChargeBill(JSONObject req) {
        if (StringUtil.isBlank(req.getString("houseNo"))) {
            return Result.error(0, "请选择房屋");
        }

        FindPage<ChargeBill> find = jdbcSession.findPage(ChargeBill.class)
                .eq(req, "houseNo")
                .like(req, "id")
                .order("paidAt", "DESC")
                .page(req);

        JDBCUtil.between(req, find, "paidAt");

        Page<ChargeBill> data = find
                .eq("payMethod", BillPayMethod.ADVANCE_PAY)
                .eq("paidState", BillPaidState.PAID)
                .eq("enableState", BillEnableState.ENABLE)
                .eq("deleted", false)
                .exe();

        List<JSONObject> result = data.getList().stream()
                .map(bill -> {
                    JSONObject v = new JSONObject();
                    v.put("id", bill.getId());
                    v.put("shouldPayDate", bill.getShouldPayDate());
                    v.put("billDateFrom", bill.getBillDateFrom());
                    v.put("billDateTo", bill.getBillDateTo());
                    v.put("shouldPayAmt", bill.getTotal());
                    v.put("paidAmt", bill.getTotal());
                    v.put("balance", getBalanceByBill(bill));
                    v.put("paidAt", Java8TimeUtils.parseString(bill.getPaidAt()));

                    return v;
                }).collect(Collectors.toList());

        Page<JSONObject> r = PageUtils.parse(data, result);

        return Result.success(r);
    }

    /**
     * 获取交易后的余额
     */
    private BigDecimal getBalanceByBill(ChargeBill bill) {

        AccWater water = jdbcSession.findOne(AccWater.class)
                .eq("orderNo", bill.getId())
                .eq("source", WaterSource.PAY_BY_ADVANCE)
                .eq("type", AccWater.DEC_AMT)
                .exe();
        if (water == null) {
            return null;
        }

        return CalculatorUtils.formatMoney(water.getAfterAmt());
    }

    /**
     * 向房屋账户手动充值
     * 增加房屋余额
     */
    @ReqMapping("/house/acc/charge")
    public Object chargeHouseAccount(Token token, JSONObject req) throws Exception {
        BigDecimal amt = req.getBigDecimal("amt");
        if (amt == null) {
            return Result.error(0, "请输入充值金额");
        }
        if (amt.compareTo(BigDecimal.ZERO) <= 0) {
            return Result.error(0, "金额须大于零");
        }
        if (CalculatorUtils.getDecimalPlace(amt) > 2) {
            return Result.error(0, "金额小数位最多支持2位");
        }
        // 附件
        JSONArray js = req.getJSONArray("fileIds");
        List<String> fileIds = js.stream()
                .map(String::valueOf)
                .filter(StringUtil::isNotBlank)
                .collect(Collectors.toList());
        if (fileIds.isEmpty()) {
            return Result.error(0, "上传凭证不能为空");
        }

        JSONObject house = basicClient.getHouseById(token, req.getString("id"));
        if (house == null) {
            return Result.error(0, "不存在的房屋id");
        }

        JSONObject community = basicClient.getCommunityById(token, house.getString("communityNo"));

        ChargeRecord cr = Pool.newInstance(ChargeRecord.class);
        cr.setCommunityNo(community.getString("id"));
        cr.setCommunityName(community.getString("name"));
        cr.setHouseNo(house.getString("id"));

        chargeRecordService.setDepartmentNo(cr, token.getCompanyNo());

        cr.setMbrCode(token.getUuid());
        cr.setMobile(token.getMobile());
        cr.setMbrName(token.getUsername());

        cr.setAmt(amt);
        cr.setResult(true);
        cr.setChargeTime(LocalDateTime.now());
        cr.setBizType(WaterSource.CHARGE_BY_CASH);
        cr.setRemark("操作终端：物业WEB端");
        jdbcSession.insert(cr);

        ChargeAnnex ca = Pool.newInstance(ChargeAnnex.class);
        ca.setEntityType(ChargeAnnexEntityType.CHARGE_RECORD);
        ca.setEntityId(cr.getId());
        ca.setType(ChargeAnnexType.MANUAL_CHARGE_VOUCHER);
        ca.setFileIds(fileIds);
        jdbcSession.insert(ca);

        return accoutService.manualIncreHouseAccount(cr, token.getUuid());
    }
}
